import { runIntervally } from '@/utils/functions/inInterval';

type Cache = Record<string, Id<RoomObjectWithId>[]>;

/**
 * 建筑 id 缓存库
 */
const cache: Cache = {};

function getStructureWithCache(room: Room, type: RoomCacheKey) {
    const accessKey = `${room.name}/${type}`;
    if (cache[accessKey] && cache[accessKey].length > 0) {
        // 有缓存，直接读取
        const result: RoomObjectWithId[] = [];
        cache[accessKey].forEach(id => {
            result.push(Game.getObjectById(id));
        });
        cache[accessKey] = result.map(obj => obj.id);
        return result;
    }
    else {
        // 没有缓存就先获取
        if (type === 'source') {
            const sources = room.find(FIND_SOURCES);
            cache[accessKey] = sources.map(s => s.id);
            return sources;
        }
        else if (type === 'mineral') {
            const minerals = room.find(FIND_MINERALS);
            cache[accessKey] = minerals.map(m => m.id);
            return minerals;
        }
        else if (type === 'tombstone') {
            const tombstones = room.find(FIND_TOMBSTONES);
            cache[accessKey] = tombstones.map(t => t.id);
            return tombstones;
        }
        else {
            const structures = room.find(FIND_STRUCTURES).filter(structure => structure.structureType === type);
            cache[accessKey] = structures.map(s => s.id);
            return structures;
        }
    }
}

/**
 * 创建建筑访问器
 *
 * @param type 建筑类型
 * @param isSingle 是否返回单个建筑
 * @author HoPGoldy
 * @see https://github.com/HoPGoldy/my-screeps-ai/blob/dev/src/modulesRoom/shortcut/createRoomShortcut.ts#L142
 */
function access(type: 'source', isSingle: false): (room: Room) => Source[];
function access(type: 'mineral'): (room: Room) => Mineral;
function access(type: 'tombstone'): (room: Room) => Tombstone[];
function access<T extends StructureCacheKey>(type: T, isSingle?: true): (room: Room) => ConcreteStructure<T>;
function access<T extends StructureCacheKey>(type: T, isSingle?: false): (room: Room) => ConcreteStructure<T>[];
function access(type: RoomCacheKey, isSingle = true) {
    return (room: Room) => {
        if (!room)
            return undefined;
        const structures = getStructureWithCache(room, type).filter(Boolean);
        return isSingle ? structures[0] : structures;
    }
}

function clearCache(type: RoomCacheKey, room: Room) {
    const accessKey = `${room.name}/${type}`;
    cache[accessKey] = [];
}


export class StructureCacheExtension extends Room {
    getContainers() {
        return access(STRUCTURE_CONTAINER, false)(this);
    }

    getController() {
        return this.controller;
    }

    getExtensions() {
        return access(STRUCTURE_EXTENSION, false)(this);
    }

    getExtractor() {
        return access(STRUCTURE_EXTRACTOR)(this);
    }

    getFactory() {
        return access(STRUCTURE_FACTORY)(this);
    }

    getLabs() {
        return access(STRUCTURE_LAB, false)(this);
    }

    getLinks() {
        return access(STRUCTURE_LINK, false)(this);
    }

    getNuker() {
        return access(STRUCTURE_NUKER)(this);
    }

    getObserver() {
        return access(STRUCTURE_OBSERVER)(this);
    }

    getPowerSpawn() {
        return access(STRUCTURE_POWER_SPAWN)(this);
    }

    getRamparts() {
        return access(STRUCTURE_RAMPART, false)(this);
    }

    getMyRamparts() {
        return this.getRamparts().filter(ram => ram.my);
    }

    getRoads() {
        return access(STRUCTURE_ROAD, false)(this);
    }

    getSpawns() {
        return access(STRUCTURE_SPAWN, false)(this);
    }

    getStorage() {
        return this.storage;
    }

    getTerminal() {
        return this.terminal;
    }

    getTombstones() {
        return access('tombstone')(this);
    }

    getTowers() {
        return access(STRUCTURE_TOWER, false)(this);
    }

    getWalls() {
        return access(STRUCTURE_WALL, false)(this);
    }

    /**
     * 获得房间里所有的 rampart 和墙壁
     */
    getBarriers() {
        return [].concat(this.getRamparts()).concat(this.getWalls());
    }

    getSources() {
        return access('source', false)(this);
    }

    getMineral() {
        return access('mineral')(this);
    }

    /**
     * 自动更新建筑与结构的缓存
     */
    updateCache() {
        // 墓碑和地上的资源很容易变，快速刷新
        runIntervally(IntervalLength.short, () => {
            clearCache('tombstone', this);
        });

        // 有一些东西是几乎不变的，但为了灵活性还是定期刷新
        runIntervally(IntervalLength.medium, () => {
            // 墙体
            clearCache('constructedWall', this);
            clearCache('rampart', this);
            // 道路
            clearCache('road', this);
        });

        // 这些建筑长期存在，刷新慢一点
        const refreshRate =
            this.controller.level <= 4 ?
                IntervalLength.medium :
                IntervalLength.long;
        const thingsToRefresh: RoomCacheKey[] = [
            'container',
            'extension',
            'extractor',
            'factory',
            'lab',
            'link',
            'nuker',
            'observer',
            'powerSpawn',
            'spawn',
            'storage',
            'terminal',
            'tower'
        ];
        // eslint-disable-next-line
        const room = this;
        runIntervally(refreshRate, () => {
            thingsToRefresh.forEach(item => this.forceUpdate(room, item));
        });
    }


    /**
     * 强制刷新，其实就是清空缓存
     */
    forceUpdate(room: Room, what: RoomCacheKey) {
        clearCache(what, room);
    }

}